﻿#ifndef LK_WINDOWS_WAS_RECORDER_//由W意波(LuoJun)编写
#define LK_WINDOWS_WAS_RECORDER_
namespace LK
{
	namespace Windows
	{
		namespace WAS
		{
			using namespace ::LK::Sound;
			/**
			@brief 录音类*/
			class Recorder :public Object
			{
				//线程同步控制
				Mutex tc;
				//音频格式转换
				Wave converter;
				//数据缓冲区
				Collection::Buffer buffer;

				//代表指定的设备
				IMMDevice *pDevice;
				//音频会话
				IAudioClient *pAudioClient;
				//音频播放客户端
				IAudioCaptureClient *pCaptureClient;
				//按时间请求音频块大小，秒为单位
				ptr<Time> hnsRequestedDuration;
				//设备块总帧数
				UINT32 bufferFrameCount;
				//声音采样率，常见的有8000，16000，22500，44100，48000，96000等
				double hz;
				//声道数，一般为2
				short ch;
				//比特数，一般为16或32
				short bits;
				//是否为浮点
				bool isFloat;
				//是否正在录音
				bool isRecording;
				//是否正在选择设备
				bool isSelecting;
				//是否已Start
				bool started;
				//是否正在关闭
				bool isClosing;


			public:
				BMETHODS(PRecorder,Recorder)
				//是否始终使用默认设备（默认设备变动时自动改用默认设备）
				bool UsingDefaultDevice;
				//混音格式，（蛋疼）
				WAVEFORMATEX CurrentFormat;
				//当前使用的设备ID*/
				ptr<String> DeviceID;
				//当前使用的设备名称*/
				ptr<String> DeviceName;
				//复制将抛出异常
				Recorder(const Recorder&) { Throw<PNotSupportException >(); }
				//赋值将抛出异常
				Recorder& operator=(const Recorder) { return RThrow<Recorder&,ptr<NotSupportException> >(); }
				/**
				@brief 构造函数，自动初始化*/
				Recorder();
				/**
				@brief 析构函数，自动关闭会话*/
				~Recorder();
				/**
				@brief 设置音量大小（vol为放大倍数，一般取0~1，大于1可能会爆破）*/
				void SetVol(double vol);
				/**
				@brief 获取当前音量大小（一般为0~1）*/
				double GetVol()const;
				/**
				@brief 获取当前采样率*/
				double GetHz()const;
				/**
				@brief 获取当前声道数*/
				short GetChannels()const;
				/**
				@brief 获取当前位数*/
				short GetBits()const;
				/**
				@brief 获取是否为浮点*/
				bool GetIsFloat()const;

				/**
				@brief 启动录音*/
				void Start();
				/**
				@brief 停止录音*/
				void Stop();
				/**
				@brief 暂停录音(与停止录音的区别在于ReaData函数不立即返回)*/
				void Pause();
				/**
				@brief 关闭会话*/
				void Close();
				/**
				@brief 清除缓存数据*/
				void Clear();
				/**
				@brief 设置输出的PCM音频格式*/
				void SetOutFormat(double hZ, short bit, short channel, bool isfloat = false);
				/**
				@brief 设置输出的PCM音频格式（使用系统的PCM格式）*/
				void SetOutFormat(const WAVEFORMATEX& fwx);
				/**
				@brief 获取当前输出的PCM音频格式，如果只想获取一个属性，其他参数可以传入NULL*/
				void GetOutFormat(int* phz, short* pbits, short* pch, bool* pisfloat = NULL);
				/**
				@brief 获取当前输出的PCM音频格式，如果只想获取一个属性，其他参数可以传入NULL*/
				void GetOutFormat(double* phz, short* pbits, short* pch, bool* pisfloat = NULL);
				/**
				@brief 获取数出音频格式*/
				WaveFormat GetOutFormat();
				/**
				@brief 获取源音格式*/
				WAVEFORMATEX& GetSourceFormat();
				/**
				@brief 获取源音格式*/
				void GetSourceFormat(int* phz, short* pbits, short* pch, bool* pisfloat = NULL);
				/**
				@brief 设置缓存时间长度*/
				void SetBufferTime(const ptr<Time>& hms);
				/**
				@brief 选择设备*/
				bool SelectDeviceById(const ptr<String> Id);
				/**
				@brief 选择设备*/
				bool SelectDeviceByName(const ptr<String>& Name);
				/**
				@brief 读取len长的数据，不读够不返回(此函数自动启动录音)*/
				PByteArray Read(int len);
				/**
				@brief 从该音源获取一段使用源音格式的音频数据包*/
				PWaveData Read();
				/**
				@brief 设备更改时重启*/
				void Restart();
				/**
				@brief 设备添加事件*/
				void OnDeviceAdded();
				/**
				@brief 设备状态改变事件*/
				void OnDeviceStateChanged();
				/**
				@brief 设备移除事件*/
				void OnDeviceRemoved();
				/**
				@brief 默认设备改变事件*/
				void OnDefaultDeviceChanged();
				/**
				@brief 设备属性改变事件*/
				void OnDevicePropertyValueChanged();
			};
			/**
			@brief 表示一个录音机*/
			class PRecorder :public ptr<Object>
			{
			public:
				/**
				@brief 使用输出音量放大倍数来创建一个新的录音机对象*/
				PRecorder(double vol) :ptr<Object>(new Recorder()){ SetVol(vol); }
				/**
				@brief 使用输出音量放大倍数、输出采样率、输出采样位数、输出声道数、是否浮点创建新的录音机对象*/
				PRecorder(double vol, double hz, short bits, short channels, bool isFloat = false) :ptr<Object>(new Recorder())
				{
					SetVol(vol); SetOutFormat(hz, bits, channels, isFloat);
				}
				/**
				@brief 设置音量大小（vol为放大倍数，一般取0~1，大于1可能会爆破）*/
				void SetVol(double vol){ Check()->SetVol(vol); }
				/**
				@brief 获取当前音量大小（一般为0~1，1为跟源音频音量相等）*/
				double GetVol()const{ return Check()->GetVol(); }
				/**
				@brief 获取当前采样率*/
				double GetHz()const{ return Check()->GetHz(); }
				/**
				@brief 获取当前声道数*/
				short GetChannels()const{ return Check()->GetChannels(); }
				/**
				@brief 获取当前位数*/
				short GetBits()const{ return Check()->GetBits(); }
				/**
				@brief 获取是否为浮点*/
				bool GetIsFloat()const{ return Check()->GetIsFloat(); }
				/**
				@brief 获取一个bool值，指示是否在默认设备更改时自动切换到新的默认设备*/
				bool GetUsingDefaultDevice()const{ return Check()->UsingDefaultDevice; }
				/**
				@brief 设置一个bool值，指示是否在默认设备更改时自动切换到新的默认设备*/
				void SetUsingDefaultDevice(bool b){ Check()->UsingDefaultDevice = b; }
				/**
				@brief 获取当前使用的音频格式*/
				WAVEFORMATEX GetCurrentFormat()const{ return Check()->CurrentFormat; }
				/**
				@brief 使用的设备ID*/
				ptr<String> GetDeviceID()const{ return Check()->DeviceID; }
				/**
				@brief 使用的设备名称*/
				ptr<String> GetDeviceName()const{ return Check()->DeviceName; }
				PMETHODS(PRecorder, Recorder);

				/**
				@brief 启动录音*/
				void Start(){ return Check()->Start(); }
				/**
				@brief 停止录音*/
				void Stop(){ return Check()->Stop(); }
				/**
				@brief 暂停录音(与停止录音的区别在于ReaData函数不立即返回)*/
				void Pause(){ return Check()->Pause(); }
				/**
				@brief 关闭会话*/
				void Close(){ return Check()->Close(); }
				/**
				@brief 清除缓存数据*/
				void Clear(){ return Check()->Clear(); }
				/**
				@brief 设置输出的PCM音频格式*/
				void SetOutFormat(double hz, short bits, short ch, bool isfloat = false){ return Check()->SetOutFormat(hz, bits, ch, isfloat); }
				/**
				@brief 设置输出的PCM音频格式（使用系统的PCM格式）*/
				void SetOutFormat(const WAVEFORMATEX& fwx){ return Check()->SetOutFormat(fwx); }
				/**
				@brief 获取当前输出的PCM音频格式，如果只想获取一个属性，其他参数可以传入NULL*/
				void GetOutFormat(int* phz, short* pbits, short* pch, bool* pisfloat = NULL){ return Check()->GetOutFormat(phz, pbits, pch, pisfloat); }
				/**
				@brief 获取当前输出的PCM音频格式，如果只想获取一个属性，其他参数可以传入NULL*/
				void GetOutFormat(double* phz, short* pbits, short* pch, bool* pisfloat = NULL){ return Check()->GetOutFormat(phz, pbits, pch, pisfloat); }
				/**
				@brief 获取数出音频格式*/
				WaveFormat GetOutFormat(){ return Check()->GetOutFormat(); }
				/**
				@brief 获取源音格式*/
				WAVEFORMATEX& GetSourceFormat(){ return Check()->GetSourceFormat(); }
				/**
				@brief 获取源音格式*/
				void GetSourceFormat(int* phz, short* pbits, short* pch, bool* pisfloat = NULL){ return Check()->GetSourceFormat(phz, pbits, pch, pisfloat); }
				/**
				@brief 设置缓存时间长度*/
				void SetBufferTime(const ptr<Time>& hms){ return Check()->SetBufferTime(hms); }
				/**
				@brief 选择设备*/
				bool SelectDeviceById(const ptr<String> id){ return Check()->SelectDeviceById(id); }
				/**
				@brief 选择设备*/
				bool SelectDeviceByName(const ptr<String>& name){ return Check()->SelectDeviceByName(name); }
				/**
				@brief 读取len长的数据，不读够不返回(此函数自动启动录音)*/
				PByteArray Read(int len){ return Check()->Read(len); }
				/**
				@brief 读取一个使用源音格式的音频数据包*/
				PWaveData Read(){ return Check()->Read(); }
				/**
				@brief 设备更改时重启*/
				void Restart(){ return Check()->Restart(); }
			};
		}
	}
}
#endif